package com.leetcode.stack_queue;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Stack;

/**
 * @author Dennis Li
 * @date 2020/9/24 23:12
 */
public class Calculate_224 {
    // 游标的影响应该全局有效，所以使用一个成员变量表示
    private int index = 0;

    public int calculate(String s) {
        // 去掉s首尾的空格部分，保证可以正常退出
        s = s.trim();
        return cal(s);
    }

    public int cal(String s) {
        Deque<Integer> stack = new LinkedList<>();
        int num = 0;
        char sign = '+';
        for (; index < s.length(); index++) {
            char c = s.charAt(index);
            if (c == ' ') {
                continue;
            } else if (isDigit(c)) {
                // 用一个递增数来记录值
                num = 10 * num + (c - '0');
            } else if (c == '(') {
                // 先对index进行自增，保证进入递归时的下一位不是'('
                index++;
                num = cal(s);
                // 退出递归时，坐标是在')'，而对于这一轮而言，c = '('，而不是')'
                // 也就是说，这个时候index在的位置是')'，而由于已经退出了递归，c的值为递归前的'('
                // 不会进入c == ')'这个判断
            }
            // 产生了相应的符号操作
            if (!isDigit(c) || index == s.length() - 1) {
                // 执行相应的计算，并进行入栈操作
                inStack(stack, num, sign);
                sign = c;
                num = 0;
            }
            if (c == ')') {
                // 仅限在递归体中适用
                break;
            }
        }
        int sum = 0;
        while (!stack.isEmpty()) {
            sum += stack.pop();
        }
        return sum;
    }

    private void inStack(Deque<Integer> stack, int num, char sign) {
        switch (sign) {
            case '+':
                stack.push(num);
                break;
            case '-':
                stack.push(-num);
                break;
            case '*':
                int product = stack.pop();
                stack.push(product * num);
                break;
            case '/':
                int division = stack.pop();
                stack.push(division / num);
        }
    }

    private boolean isDigit(char c) {
        return c >= '0' && c <= '9';
    }


    static class Solution {

        private int index = 0;

        public int calculate(String s) {
            s = s.trim();
            return cal(s);
        }

        private int cal(String s) {
            Stack<Integer> stack = new Stack<>();
            int num = 0, sum = 0;
            char op = '+';
            for (; index < s.length(); index++) {
                char c = s.charAt(index);
                if (c == ' ') continue;

                if (Character.isDigit(c)) {
                    num = num * 10 + (c - '0');
                } else if (c == '(') {
                    index++;
                    num = cal(s);
                } else if (!Character.isDigit(c) || index == s.length() - 1) {
                    inStack(stack, op, num);
                    op = c;
                    num = 0;
                }

                if (c == ')') {
                    break;
                }
            }
            while (!stack.isEmpty()) {
                sum += stack.pop();
            }
            return sum;
        }

        private void inStack(Stack<Integer> stack, char op, int num) {
            switch (op) {
                case '+':
                    stack.push(num);
                    break;
                case '-':
                    stack.push(-num);
                    break;
                case '*':
                    int multiplier = stack.pop();
                    stack.push(multiplier * num);
                    break;
                case '/':
                    int division = stack.pop();
                    stack.push(division / num);
            }
        }
    }
}
